package mysql

import (
	"context"
	"go.uber.org/zap"
	"gorm.io/gorm"
	log "maya-service/collector/logger"
	"maya-service/config"
	"maya-service/model"
	"maya-service/model/entity"
	"maya-service/utils"
)

var Order = &order{}

type order struct{}

func init() {
	Register(Order)
}

func (a *order) Init() {
	if config.Conf.AutoMigrate {
		p := &entity.Order{}
		if db.Migrator().HasTable(p) {
			log.Debug("table already exist: ", zap.String("table", p.TableName()))
			return
		}
		if err := db.AutoMigrate(p); err != nil {
			log.Error("filed to create table please check config or manually create", zap.String("table", p.TableName()), zap.String("err", err.Error()))
		} else {
			log.Info("create table successfully", zap.String("table", p.TableName()))
		}
	}
}

// Create
func (a *order) Create(ctx context.Context, m *entity.Order) (int64, error) {
	err := GetDB(ctx).Create(m).Error
	return m.Id, err
}

// Find detail
func (a *order) Find(ctx context.Context, in *model.OrderInfoRequest) (*entity.Order, error) {
	e := &entity.Order{}

	q := GetDB(ctx).Model(&entity.Order{})

	if in.Id > 0 {
		q = q.Where("id = ?", in.Id)
	}

	if in.OrderNo != "" {
		q = q.Where("order_id = ?", in.OrderNo)
	}

	if len(in.OrderStatus) > 0 {
		q = q.Where("order_status in ?", in.OrderStatus)
	}

	if in.CustomerId != "" {
		q = q.Where("customer_id = ?", in.CustomerId)
	}

	if in.ExtraData != "" {
		q = q.Where("extra_data = ?", in.ExtraData)
	}

	err := q.First(&e).Error
	return e, err
}

// Update
func (a *order) Update(ctx context.Context, in *model.OrderUpdateRequest, dict map[string]interface{}) error {
	if in.Id > 0 {
		return GetDB(ctx).Model(&entity.Order{}).Where("id = ?", in.Id).Updates(dict).Error
	}

	if in.OrderId != nil {
		return GetDB(ctx).Model(&entity.Order{}).Where("order_id = ?", in.OrderId).Updates(dict).Error
	}

	if len(in.SrcOrderStatus) > 0 && in.CustomerId != nil {
		return GetDB(ctx).Model(&entity.Order{}).Where("customer_id = ? and order_status in ?", in.CustomerId, in.SrcOrderStatus).Updates(dict).Error
	}
	return nil
}

// Delete
func (a *order) Delete(ctx context.Context, id int64) error {
	return GetDB(ctx).Delete(&entity.Order{}, id).Error
}

// List query list
func (a *order) List(ctx context.Context, in *model.OrderListRequest) (int, []*entity.Order, error) {
	var (
		q      = GetDB(ctx).Model(&entity.Order{})
		err    error
		total  int64
		orders []*entity.Order
	)

	if in.OrderId != nil {

		q = q.Where("order_id = ?", in.OrderId)

	}

	if in.CustomerId != nil {

		q = q.Where("customer_id = ?", in.CustomerId)

	}

	if in.OrderDate != nil {

		q = q.Where("order_date = ?", in.OrderDate)

	}

	if in.OrderStatus != nil {

		q = q.Where("order_status = ?", in.OrderStatus)

	}

	if in.TotalAmount != nil {

		q = q.Where("total_amount = ?", in.TotalAmount)

	}

	if in.PaymentMethod != nil {

		q = q.Where("payment_method like ?", in.PaymentMethod)

	}

	if in.ShippingAddress != nil {

		q = q.Where("shipping_address like ?", in.ShippingAddress)

	}

	if in.Remarks != nil {

		q = q.Where("remarks like ?", in.Remarks)

	}

	if in.UpdatedAt != nil {

		q = q.Where("updated_at = ?", in.UpdatedAt)

	}

	if in.OrderStatus != nil {
		q = q.Where("order_status = ?", in.OrderStatus)
	} else {
		q = q.Where("order_status in ?", []int{0, 1})
	}

	if in.CreatedAt != nil {
		zeroUnix := utils.ZeroUnix(*in.CreatedAt)
		q = q.Where("created_at >  ? and created_at <?", zeroUnix, zeroUnix+24*3600)
	}

	q = q.Order("order_status asc, created_at desc")
	if err = q.Count(&total).Error; err != nil {
		return 0, nil, err
	}
	if err = q.Limit(in.Size).Offset((in.Index - 1) * in.Size).Find(&orders).Error; err != nil {
		return 0, nil, err
	}
	return int(total), orders, nil
}

// ExecTransaction execute database transaction
func (a *order) ExecTransaction(ctx context.Context, callback func(ctx context.Context) error) error {
	return GetDB(ctx).Transaction(func(tx *gorm.DB) error {
		ctx = context.WithValue(ctx, ContextTxKey, tx)
		return callback(ctx)
	})
}
